Hi Alexey,
Yes I believe the problem is because it is trying to make too big and sudden steps. For example if the Dest is all of a sudden changed by 100 microsteps then KFLOP will output pulses at a high rate (over 1 MHz) to be at the desired destination by the next 90us servo sample time. This most likely stalls your stepper motor and results in no or little actual motion (or actually unless the step pulse is set really short pulses at this rate would be overlapped into one big pulse). Because you are running closed loop the Servo loop detects that the encoder indicates that the motor is at the wrong position due to lost steps. It then makes a gradual output correction based on the Integrator Rate. Once the
Integrator has made the maximum allowed amount of correction (MaxI) further errors will then go uncorrected.
Instead of changing the Dest directly in steps try using the MoveExp() command to move. This will essentially low pass filter the big commanded steps into smoother motion distributed over many servo samples. The Time Constant Tau can be adjusted to apply more or less smoothing (and consequently more or less lag). See the MPGSmooth.c for an example.
Regards
TK
Group: DynoMotion |
Message: 5334 |
From: erry321 |
Date: 6/26/2012 |
Subject: Re: MPG question |
Thanks Tom
I have come up with the following code:
for (;;) //loop forever
{
WaitNextTimeSlice();
T=T+1;
float LastState = persist.UserData[98]; // get last state
if (chan[5].Enable) // is the axis enabled??
{
SetBit(27);
NewOutput = chan[5].Output;
if (NewOutput<0)
{
NewOutput=-NewOutput;
SetBit(28);
}
else
{
ClearBit(28);
}
FPGA(IO_PWMS+0) = NewOutput+32;
}
else
{
FPGA(IO_PWMS+0) = 32; // whenever not enabled put to 0 RPM
ClearBit(27); // all off
ClearBit(28);
}
// MPG processing
if (T>10)
{
Mpg_Pos_Current = ch6->Position;
X_Pos_Current = ch0->Position;
Y_Pos_Current = ch1->Position;
Z_Pos_Current = ch2->Position;
if (ReadBit(19)) // is X1 selected?
{
Factor = 2;
TAU=0.01;
}
else if (ReadBit(20)) // is X10 selected?
{
Factor = 20;
TAU=0.03;
}
else if (ReadBit(21)) // is X100 selected?
{
Factor = 200;
TAU=0.05;
}
else Factor = 0;
if (ReadBit(14)) // if button pressed ignore the encoder.
Mpg_Pos_Current = 0;
Mpg_Pos_Change = Mpg_Pos_Current;
Mpg_Pos_Change_Final = Mpg_Pos_Change*Factor;
if (ReadBit(16)) // is x selected?
{
MoveExp(0,X_Pos_Current-Mpg_Pos_Change_Final,TAU);
while (CheckDone(0));
}
else if (ReadBit(17)) // is y selected?
{
MoveExp(1,Y_Pos_Current-Mpg_Pos_Change_Final,TAU);
while (CheckDone(1));
}
else if (ReadBit(18)) // is z selected?
{
MoveExp(2,Z_Pos_Current+Mpg_Pos_Change_Final,TAU);
while (CheckDone(2));
}
T=0;
Zero(6);
}
}
The only issue with MoveExp, you can not be sure what every turn would give you the same movement, so I can not rely on the MPG ring scale and have to watch the coordinates on the screen all the time.
|
|
Group: DynoMotion |
Message: 5342 |
From: Tom Kerekes |
Date: 6/26/2012 |
Subject: Re: MPG question |
Hi Alexey,
That is because of the way you wrote the progam it doesn't really have anything to do with the MoveExp() function. Your program essentially makes a new relative move while the motion is still in progress so the total amount of motion will be unpredictable. I think a better way is to maintain an absolute "target" position that is driven more directly from the encoder motion like the original MPGSmooth.c. I've tried to modify the MPGSmooth.c program to use a Hardware Encoder input and changed it for your input bits. See the attached MPGSMoothHardwareEnc.c. Please try that. It isn't tested :}
On a minor note: The MoveExp() command never completes. It converges forever. That is why the program is written to detect no encoder motion for 1 sec and then do a final move of the last little bit. The logic for your
while (CheckDone(0)) ;
was backwards so it never waited at all.
Hope this works better.
TK
Group: DynoMotion |
Message: 5347 |
From: Alexey Volkov |
Date: 6/26/2012 |
Subject: Re: MPG question [1 Attachment] |
Hello Tom
It works perfectly, thanks a lot! The only thing I had to modify is the direction control:I need X and Y going in negative direction and Z in positive.
if (ReadBit(SELECTX)) // is x selected? { Axis=0; Dir=-1;
} else if (ReadBit(SELECTY)) // is y selected? {
Axis=1; Dir=-1; }
else if (ReadBit(SELECTZ)) // is z selected? { Axis=2;
Dir=1; }
// check if the Axis just changed or we have been
// converging to the target for a long time if (Axis != LastAxis || (InMotion && Time_sec() > LastChangeTime+FINAL_TIME))
{ if (InMotion) Move(LastAxis,Target); //finalize any motion
LastAxis = Axis; InMotion = FALSE;
} if (Change1) // did we move?
{ if (!InMotion) Target = chan[Axis].Dest; Target += Change1 * Factor*Dir;
MoveExp(Axis,Target,TAU); // note: contains a WaitNextTimeSlice LastChangeTime = Time_sec();
InMotion=TRUE; }
Best regards, Alexey
On Tue, Jun 26, 2012 at 8:13 PM, Tom Kerekes <tk@...> wrote:
[Attachment(s) from Tom Kerekes included below]
Hi Alexey,
That is because of the way you wrote the progam it doesn't really have anything to do with the MoveExp() function. Your program essentially makes a new relative move while the motion is still in progress so the total amount of motion will be unpredictable. I think a better way is to maintain an absolute "target" position that is driven more directly from the encoder motion like the original MPGSmooth.c. I've tried to modify the MPGSmooth.c program to use a Hardware Encoder input and changed it for your input bits. See the attached MPGSMoothHardwareEnc.c. Please try that. It isn't tested :}
On a minor note: The MoveExp() command never completes. It converges forever. That is why the program is written to detect no encoder motion for 1 sec and then do a final move of the last little bit. The logic for your
while (CheckDone(0)) ;
was backwards so it never waited at all.
Hope this works better.
TK
Group: DynoMotion |
Message: 9957 |
From: lovethebuzz69 |
Date: 8/12/2014 |
Subject: MPG question |
Hi Folks,I humbly request your help getting my MPG to work. I just do not understand the C code enough to figure out what is happening. I have tried every way I can think of to get the Kflop/Kanalog combination to service the MPG.Using the MPGSmoothHardwareEnc.c example I modified the the code to match my configuration of the x axis (ch1). The MPG is connected to the axis 7 encoder input of the Kanalog. The MPG generates counts that show up in the Axis screen under axis 7. In the code I set the MPG_INPUT_AXIS = 7 and the other defines to match the bits I am using for the SelectX, Y, and Z, and for the Factor1, 10 and 100.Any help would be greatly appreciated.Here is the code I am currently trying to use just to jog the X axis to start with. Hopefully from there I can figure out Y, Z, and A.ThanksRick#include "KMotionDef.h"// Example Init program that includes "smooth" MPG motion example// which makes use of the exponential motion command.#define MPG_INPUT_AXIS 7#define TAU 0.08 // smoothness factor (Low Pass Time constant seconds)#define FINAL_TIME 1.0 // Set final dest after this amount of time with no change#define ENABLE_MPG 140#define SELECTX 128#define SELECTY 129#define SELECTZ 130#define FACTOR1 131#define FACTOR10 132#define FACTOR100 133main(){ int Change1, NewPos, Pos; int InMotion=FALSE,Axis,LastAxis=-1; double LastChangeTime=0,Target,Factor=0; ch1->InputMode=ENCODER_MODE; ch1->OutputMode=DAC_SERVO_MODE; ch1->Vel=40000; ch1->Accel=400000; ch1->Jerk=600000; ch1->P=1; ch1->I=0; ch1->D=10; ch1->FFAccel=0; ch1->FFVel=0; ch1->MaxI=2000; ch1->MaxErr=1e+008; ch1->MaxOutput=2000; ch1->DeadBandGain=1; ch1->DeadBandRange=0; ch1->InputChan0=1; ch1->InputChan1=1; ch1->OutputChan0=1; ch1->OutputChan1=1; ch1->MasterAxis=-1; ch1->LimitSwitchOptions=0x103; ch1->LimitSwitchNegBit=136; ch1->LimitSwitchPosBit=136; ch1->SoftLimitPos=1e+009; ch1->SoftLimitNeg=-1e+009; ch1->InputGain0=1; ch1->InputGain1=1; ch1->InputOffset0=0; ch1->InputOffset1=0; ch1->OutputGain=1; ch1->OutputOffset=0; ch1->SlaveGain=1; ch1->BacklashMode=BACKLASH_OFF; ch1->BacklashAmount=0; ch1->BacklashRate=0; ch1->invDistPerCycle=1; ch1->Lead=0; ch1->MaxFollowingError=10000; ch1->StepperAmplitude=250; ch1->iir[0].B0=1; ch1->iir[0].B1=0; ch1->iir[0].B2=0; ch1->iir[0].A1=0; ch1->iir[0].A2=0; ch1->iir[1].B0=1; ch1->iir[1].B1=0; ch1->iir[1].B2=0; ch1->iir[1].A1=0; ch1->iir[1].A2=0; ch1->iir[2].B0=0.0166094; ch1->iir[2].B1=0.0332189; ch1->iir[2].B2=0.0166094; ch1->iir[2].A1=1.60679; ch1->iir[2].A2=-0.673229; EnableAxisDest(1,0); EnableAxisDest(1,ch1->Position); DefineCoordSystem(1,-1,-1,-1); Pos = chan[MPG_INPUT_AXIS].Position; for (;;) { NewPos = chan[MPG_INPUT_AXIS].Position; Change1 = NewPos - Pos; Pos = NewPos; if (ReadBit(ENABLE_MPG)) // if button pressed ignore the encoder. Change1 = 0; else if (ReadBit(FACTOR1)) // is X1 selected? Factor = 2; else if (ReadBit(FACTOR10)) // is X10 selected? Factor = 20; else if (ReadBit(FACTOR100)) // is X100 selected? Factor = 200; else Factor = 0.0; if (ReadBit(SELECTX)) // is x selected? Axis=0; else if (ReadBit(SELECTY)) // is y selected? Axis=1; else if (ReadBit(SELECTZ)) // is z selected? Axis=2; // check if the Axis just changed or we have been // converging to the target for a long time if (Axis != LastAxis || (InMotion && Time_sec() > LastChangeTime+FINAL_TIME)) { if (InMotion) Move(LastAxis,Target); //finalize any motion LastAxis = Axis; InMotion = FALSE; } if (Change1) // did we move? { if (!InMotion) Target = chan[Axis].Dest; Target += Change1 * Factor; MoveExp(Axis,Target,TAU); // note: contains a WaitNextTimeSlice LastChangeTime = Time_sec(); InMotion=TRUE; } else { WaitNextTimeSlice(); } } return 0;}
|
|
Group: DynoMotion |
Message: 9958 |
From: Tom Kerekes |
Date: 8/12/2014 |
Subject: Re: MPG question |
Hi lovethebuzz69,
Your post is hard to read.
It seems your X axis is Axis 1. Normally X would be Axis 0.
As coded to move Axis 1 SELECTY (Input bit 129) would need to be active. Have you checked on the Digital IO Screen if 129 is checked?
Also:
The ENABLE_MPG 140 must be unchecked The SELECTX 128 must be unchecked One of the FACTORS 131, 132, 133 must be checked.
Have you verified this?
Regards TK
From: "lovethebuzz69@... [DynoMotion]" <DynoMotion@yahoogroups.com> To: DynoMotion@yahoogroups.com Sent: Tuesday, August 12, 2014 5:11 PM Subject: [DynoMotion] MPG question
Hi Folks,I humbly request your help getting my MPG to work. I just do not understand the C code enough to figure out what is happening. I have tried every way I can think of to get the Kflop/Kanalog combination to service the MPG.Using the MPGSmoothHardwareEnc.c example I modified the the code to match my configuration of the x axis (ch1). The MPG is connected to the axis 7 encoder input of the Kanalog. The MPG generates counts that show up in the Axis screen under axis 7. In the code I set the MPG_INPUT_AXIS = 7 and the other defines to match the bits I am using for the SelectX, Y, and Z, and for the Factor1, 10 and 100.Any help would be greatly appreciated.Here is the code I am currently trying to use just to jog the X axis to start with. Hopefully from there I can figure out Y, Z, and A.ThanksRick#include "KMotionDef.h"// Example Init program that includes "smooth" MPG motion example// which makes use of the
exponential motion command.#define MPG_INPUT_AXIS 7#define TAU 0.08 // smoothness factor (Low Pass Time constant seconds)#define FINAL_TIME 1.0 // Set final dest after this amount of time with no change#define ENABLE_MPG 140#define SELECTX 128#define SELECTY 129#define SELECTZ 130#define FACTOR1 131#define FACTOR10 132#define FACTOR100 133main(){ int Change1, NewPos, Pos; int InMotion=FALSE,Axis,LastAxis=-1; double LastChangeTime=0,Target,Factor=0; ch1->InputMode=ENCODER_MODE; ch1->OutputMode=DAC_SERVO_MODE; ch1->Vel=40000; ch1->Accel=400000; ch1->Jerk=600000; ch1->P=1; ch1->I=0; ch1->D=10; ch1->FFAccel=0; ch1->FFVel=0; ch1->MaxI=2000;
ch1->MaxErr=1e+008; ch1->MaxOutput=2000; ch1->DeadBandGain=1; ch1->DeadBandRange=0; ch1->InputChan0=1; ch1->InputChan1=1; ch1->OutputChan0=1; ch1->OutputChan1=1; ch1->MasterAxis=-1; ch1->LimitSwitchOptions=0x103; ch1->LimitSwitchNegBit=136; ch1->LimitSwitchPosBit=136; ch1->SoftLimitPos=1e+009; ch1->SoftLimitNeg=-1e+009; ch1->InputGain0=1; ch1->InputGain1=1; ch1->InputOffset0=0; ch1->InputOffset1=0; ch1->OutputGain=1; ch1->OutputOffset=0; ch1->SlaveGain=1; ch1->BacklashMode=BACKLASH_OFF;
ch1->BacklashAmount=0; ch1->BacklashRate=0; ch1->invDistPerCycle=1; ch1->Lead=0; ch1->MaxFollowingError=10000; ch1->StepperAmplitude=250; ch1->iir[0].B0=1; ch1->iir[0].B1=0; ch1->iir[0].B2=0; ch1->iir[0].A1=0; ch1->iir[0].A2=0; ch1->iir[1].B0=1; ch1->iir[1].B1=0; ch1->iir[1].B2=0; ch1->iir[1].A1=0; ch1->iir[1].A2=0; ch1->iir[2].B0=0.0166094; ch1->iir[2].B1=0.0332189; ch1->iir[2].B2=0.0166094; ch1->iir[2].A1=1.60679; ch1->iir[2].A2=-0.673229; EnableAxisDest(1,0);
EnableAxisDest(1,ch1->Position); DefineCoordSystem(1,-1,-1,-1); Pos = chan[MPG_INPUT_AXIS].Position; for (;;) { NewPos = chan[MPG_INPUT_AXIS].Position; Change1 = NewPos - Pos; Pos = NewPos; if (ReadBit(ENABLE_MPG)) // if button pressed ignore the encoder. Change1 = 0; else if (ReadBit(FACTOR1)) // is X1 selected? Factor = 2; else if (ReadBit(FACTOR10)) // is X10 selected? Factor = 20; else if
(ReadBit(FACTOR100)) // is X100 selected? Factor = 200; else Factor = 0.0; if (ReadBit(SELECTX)) // is x selected? Axis=0; else if (ReadBit(SELECTY)) // is y selected? Axis=1; else if (ReadBit(SELECTZ)) // is z selected? Axis=2; // check if the Axis just changed or we have been // converging to the target for a long
time if (Axis != LastAxis || (InMotion && Time_sec() > LastChangeTime+FINAL_TIME)) { if (InMotion) Move(LastAxis,Target); //finalize any motion LastAxis = Axis; InMotion = FALSE; } if (Change1) // did we move? { if (!InMotion) Target = chan[Axis].Dest; Target += Change1 *
Factor; MoveExp(Axis,Target,TAU); // note: contains a WaitNextTimeSlice LastChangeTime = Time_sec(); InMotion=TRUE; } else { WaitNextTimeSlice(); } } return 0;}
|
|
Group: DynoMotion |
Message: 9962 |
From: lovethebuzz69 |
Date: 8/13/2014 |
Subject: Re: MPG question |
Hi Tom,
Sorry about the screwed up post.
Everything looked find when I pasted in the code.
Anyway, ch1 is my X axis. For some reason ch0 on my Kanalog does not work.
Well, now I think I see the problem. As soon as you said
"As coded to move Axis 1 SELECTY (Input bit 129) would need to be active.
The code says:
if (ReadBit(SELECTX)) // is x selected?
Axis=0;
else if (ReadBit(SELECTY)) // is y selected?
Axis=1;
else if (ReadBit(SELECTZ)) // is z selected?
Axis=2;
Since my Axis 1 is the X axis, these values need to be changed to match my setup. Correct?
I was activating Bit 128 expecting channel 1 to be the selected channel but the code is waiting for Bit 129 to move channel 1.
I will fix that tonight and give it a try.
Thanks
Rick
|
|
Group: DynoMotion |
Message: 9964 |
From: Tom Kerekes |
Date: 8/13/2014 |
Subject: Re: MPG question |
Hi Rick,
In this case you should probably change to:
if (ReadBit(SELECTX)) // is x selected?
Axis=1;
else if (ReadBit(SELECTY)) // is y selected?
Axis=2;
else if (ReadBit(SELECTZ)) // is z selected?
Axis=3;
Regards TK
From: "lovethebuzz69@... [DynoMotion]" <DynoMotion@yahoogroups.com> To: DynoMotion@yahoogroups.com Sent: Wednesday, August 13, 2014 9:53 AM Subject: Re: [DynoMotion] MPG question
Hi Tom,
Sorry about the screwed up post.
Everything looked find when I pasted in the code.
Anyway, ch1 is my X axis. For some reason ch0 on my Kanalog does not work.
Well, now I think I see the problem. As soon as you said
"As coded to move Axis 1 SELECTY (Input bit 129) would need to be active.
The code says:
if (ReadBit(SELECTX)) // is x selected?
Axis=0;
else if (ReadBit(SELECTY)) // is y selected?
Axis=1;
else if (ReadBit(SELECTZ)) // is z selected?
Axis=2;
Since my Axis 1 is the X axis, these values need to be changed to match my setup. Correct?
I was activating Bit 128 expecting channel 1 to be the selected channel but the code is waiting for Bit 129 to move channel 1.
I will fix that tonight and give it a try.
Thanks
Rick
|
|
| | | | | |